Executive Summary

The goal of this project is to determine the states that are most in need of electric vehicle stations based on a number of factors. These factors include the current number of stations, number of electric vehicle registrations, and state population. Results from this project should identify the states most in need of adding electric vehicle charging stations.


Part 1: Cleaning & Exploratory Data Analysis


import libraries and dataset EV Station Data: https://afdc.energy.gov/data_download


library(tidyverse)
library(dplyr)
library(janitor)
library(Hmisc)
library(ggplot2)

alt_fuel_stations <- read_csv("data/alt_fuel_stations (Jul 7 2025).csv")
alt_fuel_stations

set random state seed

set.seed(42)

clean columns names using janitor

alt_fuel_stations_clean <- clean_names(alt_fuel_stations)

alt_fuel_stations_clean

filter to only EV stations (“ELEC”)

ev_stations <- filter(alt_fuel_stations_clean, fuel_type_code == "ELEC")

ev_stations

take a look at the values

summary(ev_stations)
 fuel_type_code     station_name       street_address     intersection_directions     city              state               zip             plus4         station_phone     
 Length:87392       Length:87392       Length:87392       Length:87392            Length:87392       Length:87392       Length:87392       Mode:logical   Length:87392      
 Class :character   Class :character   Class :character   Class :character        Class :character   Class :character   Class :character   NA's:87392     Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character        Mode  :character   Mode  :character   Mode  :character                  Mode  :character  
                                                                                                                                                                            
                                                                                                                                                                            
                                                                                                                                                                            
                                                                                                                                                                            
 status_code        expected_date  groups_with_access_code access_days_time   cards_accepted      bd_blends         ng_fill_type_code     ng_psi          ev_level1_evse_num
 Length:87392       Mode:logical   Length:87392            Length:87392       Length:87392       Length:87392       Length:87392       Length:87392       Mode:logical      
 Class :character   NA's:87392     Class :character        Class :character   Class :character   Class :character   Class :character   Class :character   TRUE:46           
 Mode  :character                  Mode  :character        Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character   NA's:87346        
                                                                                                                                                                            
                                                                                                                                                                            
                                                                                                                                                                            
                                                                                                                                                                            
 ev_level2_evse_num ev_dc_fast_count  ev_other_info   ev_network        ev_network_web     geocode_status        latitude       longitude       date_last_confirmed 
 Min.   :  1.000    Min.   :  1.000   Mode:logical   Length:87392       Length:87392       Length:87392       Min.   :18.00   Min.   :-162.29   Min.   :2017-09-06  
 1st Qu.:  2.000    1st Qu.:  1.000   NA's:87392     Class :character   Class :character   Class :character   1st Qu.:34.42   1st Qu.:-117.75   1st Qu.:2025-07-07  
 Median :  2.000    Median :  2.000                  Mode  :character   Mode  :character   Mode  :character   Median :39.72   Median : -87.64   Median :2025-07-07  
 Mean   :  2.558    Mean   :  4.268                                                                           Mean   :39.27   Mean   : -94.69   Mean   :2025-04-13  
 3rd Qu.:  2.000    3rd Qu.:  6.000                                                                           3rd Qu.:43.05   3rd Qu.: -77.09   3rd Qu.:2025-07-07  
 Max.   :102.000    Max.   :120.000                                                                           Max.   :68.38   Max.   : -52.70   Max.   :2025-07-07  
 NA's   :13353      NA's   :72204                                                                                                               NA's   :212         
       id          updated_at        owner_type_code    federal_agency_id federal_agency_name   open_date          hydrogen_status_link ng_vehicle_class   lpg_primary   
 Min.   :  1523   Length:87392       Length:87392       Mode:logical      Mode:logical        Min.   :1995-08-30   Length:87392         Length:87392       Mode:logical  
 1st Qu.:174654   Class :character   Class :character   NA's:87392        NA's:87392          1st Qu.:2020-11-05   Class :character     Class :character   NA's:87392    
 Median :232795   Mode  :character   Mode  :character                                         Median :2022-07-08   Mode  :character     Mode  :character                 
 Mean   :246649                                                                               Mean   :2021-11-28                                                         
 3rd Qu.:331404                                                                               3rd Qu.:2024-01-13                                                         
 Max.   :405532                                                                               Max.   :2025-10-15                                                         
                                                                                              NA's   :248                                                                
 e85_blender_pump ev_connector_types   country          intersection_directions_french access_days_time_french bd_blends_french groups_with_access_code_french
 Mode:logical     Length:87392       Length:87392       Length:87392                   Length:87392            Mode:logical     Length:87392                  
 NA's:87392       Class :character   Class :character   Class :character               Class :character        NA's:87392       Class :character              
                  Mode  :character   Mode  :character   Mode  :character               Mode  :character                         Mode  :character              
                                                                                                                                                              
                                                                                                                                                              
                                                                                                                                                              
                                                                                                                                                              
 hydrogen_is_retail access_code        access_detail_code federal_agency_code facility_type      cng_dispenser_num cng_on_site_renewable_source
 Mode:logical       Length:87392       Length:87392       Mode:logical        Length:87392       Min.   : NA       Length:87392                
 NA's:87392         Class :character   Class :character   NA's:87392          Class :character   1st Qu.: NA       Class :character            
                    Mode  :character   Mode  :character                       Mode  :character   Median : NA       Mode  :character            
                                                                                                 Mean   :NaN                                   
                                                                                                 3rd Qu.: NA                                   
                                                                                                 Max.   : NA                                   
                                                                                                 NA's   :87392                                 
 cng_total_compression_capacity cng_storage_capacity lng_on_site_renewable_source e85_other_ethanol_blends  ev_pricing        ev_pricing_french  lpg_nozzle_types  
 Min.   : NA                    Min.   : NA          Mode:logical                 Length:87392             Length:87392       Length:87392       Length:87392      
 1st Qu.: NA                    1st Qu.: NA          NA's:87392                   Class :character         Class :character   Class :character   Class :character  
 Median : NA                    Median : NA                                       Mode  :character         Mode  :character   Mode  :character   Mode  :character  
 Mean   :NaN                    Mean   :NaN                                                                                                                        
 3rd Qu.: NA                    3rd Qu.: NA                                                                                                                        
 Max.   : NA                    Max.   : NA                                                                                                                        
 NA's   :87392                  NA's   :87392                                                                                                                      
 hydrogen_pressures hydrogen_standards cng_fill_type_code   cng_psi          cng_vehicle_class  lng_vehicle_class ev_on_site_renewable_source restricted_access
 Length:87392       Length:87392       Length:87392       Length:87392       Length:87392       Mode:logical      Length:87392                Mode :logical    
 Class :character   Class :character   Class :character   Class :character   Class :character   NA's:87392        Class :character            FALSE:13273      
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character                     Mode  :character            TRUE :1805       
                                                                                                                                              NA's :72314      
                                                                                                                                                               
                                                                                                                                                               
                                                                                                                                                               
  rd_blends         rd_blends_french rd_blended_with_biodiesel rd_maximum_biodiesel_level nps_unit_name  cng_station_sells_renewable_natural_gas
 Length:87392       Mode:logical     Length:87392              Min.   : NA                Mode:logical   Mode:logical                           
 Class :character   NA's:87392       Class :character          1st Qu.: NA                NA's:87392     NA's:87392                             
 Mode  :character                    Mode  :character          Median : NA                                                                      
                                                               Mean   :NaN                                                                      
                                                               3rd Qu.: NA                                                                      
                                                               Max.   : NA                                                                      
                                                               NA's   :87392                                                                    
 lng_station_sells_renewable_natural_gas maximum_vehicle_class ev_workplace_charging funding_sources   
 Mode:logical                            Length:87392          Mode :logical         Length:87392      
 NA's:87392                              Class :character      FALSE:86855           Class :character  
                                         Mode  :character      TRUE :534             Mode  :character  
                                                               NA's :3                                 
                                                                                                       
                                                                                                       
                                                                                                       

select columns for study (simple set at first) goal: where are the stations, how many of them are there per state

ev_stations_selected <- ev_stations |>
  select(station_name, city, state, zip, country, latitude, longitude, ev_network)

ev_stations_selected

look at selected columns

summary(ev_stations_selected)
 station_name           city              state               zip              country             latitude       longitude        ev_network       
 Length:87392       Length:87392       Length:87392       Length:87392       Length:87392       Min.   :18.00   Min.   :-162.29   Length:87392      
 Class :character   Class :character   Class :character   Class :character   Class :character   1st Qu.:34.42   1st Qu.:-117.75   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character   Mode  :character   Median :39.72   Median : -87.64   Mode  :character  
                                                                                                Mean   :39.27   Mean   : -94.69                     
                                                                                                3rd Qu.:43.05   3rd Qu.: -77.09                     
                                                                                                Max.   :68.38   Max.   : -52.70                     

check for missing values

sum(is.na(ev_stations_selected))
[1] 0

now, just US market

ev_stations_us <- filter(ev_stations_selected, country == "US")
ev_stations_us

look at different networks (checking for Tesla and Electrify America)

ev_networks <- ev_stations_us[ ,"ev_network"]
table(ev_networks)
ev_network
                7CHARGE                     ABM                AMPED_UP                   AMPUP              APPLEGREEN                   AUTEL           Blink Network 
                     41                      61                       5                     581                      35                      59                    5484 
               BP_PULSE                  CHAEVI               CHARGELAB               CHARGENET     ChargePoint Network          CHARGESMART_EV                CHARGEUP 
                     51                       3                     188                       3                   41702                     226                     286 
                CHARGIE                CIRCLE_K               DIRT_ROAD            ELECTRIC_ERA       Electrify America              Enel X Way             ENVIROSPARK 
                      7                      86                       1                      17                    1076                       5                       3 
          EPIC_CHARGING              EV Connect                  EVBOLT                    EVCS               EVGATEWAY            eVgo Network                   EVIUM 
                     17                    1427                      15                     249                     401                    1079                      18 
                EVMATCH                   EVOKE              EVPASSPORT                 EVPOWER                 EVRANGE                     FCN                   FLASH 
                     52                     217                       2                       5                      38                     192                     139 
                FLITWAY                     FLO             FORD_CHARGE                   FPLEV          GRAVITI_ENERGY GRAVITY_CHARGING_CENTER            HONEY_BADGER 
                      8                    1072                     202                      49                      64                       1                       1 
              HYPERFUEL               IN_CHARGE                   IONNA                    JULE             KWIK_CHARGE                    LOOP                  MATCHA 
                      7                       7                      20                       6                       5                     915                       1 
          Non-Networked                  NOODOE               OpConnect               POWERFLEX           POWERPORT_EVC               POWERPUMP                   RED_E 
                   5790                     253                     334                     169                       9                       3                     551 
                  REVEL              REVITALIZE        RIVIAN_ADVENTURE        RIVIAN_WAYPOINTS                    ROVE          SHELL_RECHARGE           STAY_N_CHARGE 
                      6                       6                     119                     190                       1                    1503                      55 
                  SWTCH                   Tesla       Tesla Destination             TURNONGREEN               UNIVERSAL                 VIALYNK                 WATT_EV 
                    219                    2690                    4717                      66                     256                     599                       5 
                 ZEFNET 
                    265 

filter to only contiguous US for geospatial analysis

EXPORT FOR GEOSPATIAL ANALYSIS

ev_stations_geo <- ev_stations_us |>
  filter(!state %in% c("AK", "PR", "HI"))

unique(ev_stations_geo$state)
 [1] "CA" "VT" "WA" "OR" "IL" "ID" "WI" "IA" "TX" "SC" "CT" "OH" "WV" "MO" "UT" "KS" "FL" "MA" "CO" "MI" "NC" "VA" "TN" "AL" "AZ" "GA" "MD" "MN" "AR" "NJ" "RI" "PA" "LA"
[34] "DC" "NY" "ME" "NH" "KY" "NE" "MS" "SD" "DE" "IN" "OK" "NM" "MT" "ND" "NV" "WY"
write.csv(ev_stations_geo, "data/ev_station_locations.csv")

breakdown by state for upcoming joins

ev_stations_by_state <- ev_stations_us |>
  group_by(state) |>
  summarise(total_stations = n()) |>
  arrange(desc(total_stations))

ev_stations_by_state

for plotting (top 10 only)

ev_stations_by_state_10 <- ev_stations_us |>
  group_by(state) |>
  summarise(total_stations = n()) |>
  arrange(desc(total_stations)) |>
  head(10)

time to plot


ggplot(ev_stations_by_state_10, aes(x = reorder(state, -total_stations), y = total_stations)) + 
  geom_bar(stat = "identity", fill = "steelblue") +
  labs(
    title = "Top 10 States by Total EV Stations",
    x = "State",
    y = "EV Stations"
  ) + 
  geom_text(aes(label = total_stations), vjust = -0.2)
ggsave("outputs/top_10_states_total_ev_stations.png")

visualize US charging stations

library(maps)

ggplot(ev_stations_us, aes(x = longitude, y = latitude)) +
  borders("state") +
  geom_point(alpha = 0.2, color = "green", size = 0.3) +
  coord_fixed(1.3) + 
  labs(title = "US EV Charging Stations")

ggsave("outputs/us_ev_charging_station_map.png")

import data on number of vehicle registrations by state EV Registration Data: https://afdc.energy.gov/data/10962

ev_registrations <- read_csv("data/ev_registration_by_state.csv")
ev_registrations <- clean_names(ev_registrations)
ev_registrations

drop total and DC rows

ev_registrations_50 <- ev_registrations[!(ev_registrations$state) %in% c("District of Columbia", "Total"),]
ev_registrations_50

change state names to abbreviations

ev_registrations_50$state <- state.abb[match(ev_registrations_50$state, state.name)]
ev_registrations_50

compare total number of ev stations to number of registrations by joining on state drop PR and DC

ev_combined <- ev_stations_by_state |>
  left_join(ev_registrations_50)

ev_combined <- ev_combined[!(ev_combined$state) %in% c("PR", "DC"),]

ev_combined

sort by registrations, descending

ev_combined <- ev_combined |>
  arrange(desc(ev_combined$registration_count))

ev_combined

import population information

State Population Data: https://www.census.gov/data/tables/time-series/demo/popest/2020s-state-total.html

state_populations <- read_csv("data/state_populations.csv")
state_populations

change state names to abbreviations, again

state_populations$state <- state.abb[match(state_populations$state, state.name)]
state_populations

join population data to existing combined dataset

ev_combined_pop <- ev_combined |>
  left_join(state_populations)

ev_combined_pop 

begin simple analysis

goal: calculate electric vehicles per station for each state

ev_combined_pop <- ev_combined_pop |>
  mutate(evs_per_station = round(registration_count / total_stations, 2)) |>
  arrange(desc(evs_per_station))

ev_combined_pop

goal: calculate number of people per station based on population

ev_combined_pop <- ev_combined_pop |>
  mutate(people_per_station = round(population / total_stations, 2)) |>
  arrange(desc(people_per_station))

ev_combined_pop

goal: calculate percentage of population with an EV (rough estimate as population includes all ages and some owners may have more than one EV)

ev_combined_pop <- ev_combined_pop |>
  mutate(pop_with_ev = round(registration_count / population, 4)) |>
  arrange(desc(pop_with_ev))

ev_combined_pop

ev_stats <- ev_combined_pop # for later use

export finalized data frame for modeling

write.csv(ev_combined_pop, "data/ev_combined_pop.csv")
write.csv(ev_stats, "data/ev_stats.csv")

visualize with heat map show states with largest proportion of EVs to the available charging stations these states may be underdeveloped and in need of additional EV station rollout yellow and orange states may need more stations based on the number of vehicles currently registered

library(usmap)

plot_usmap(data = ev_combined_pop, values = "evs_per_station", color = "white") + 
  scale_fill_viridis_c(option = "C") +
  labs(title = "EVs Per Charging Station in the US",
       fill = "EVs/Station")

ggsave("outputs/evs_per_charging_station_us.png", bg = "grey")

visualize with heat map show states with the largest proportion of people to the available charging stations these states have the highest populations relative to the number of stations yellow and orange states may be in need of more EV stations based on state population

plot_usmap(data = ev_combined_pop, values = "people_per_station", color = "white") + 
  scale_fill_viridis_c(option = "C") +
  labs(title = "People Per Charging Station in the US",
       fill = "People/Station")

ggsave("outputs/people_per_charging_station_us.png", bg = "grey")

visualize with heat map show states with the largest highest EV saturation (EV registrations / population) yellow and orange states could be considered the faster-growing markets compared to purple and blue states as expected, California has the highest saturation of EVs followed by other Pacific Coast states other states may see jumps in saturation in the coming decades and would require additional EV stations

plot_usmap(data = ev_combined_pop, values = "pop_with_ev", color = "white") + 
  scale_fill_viridis_c(option = "C") +
  labs(title = "EV Saturation by Population",
       fill = "EV Reg/Pop")

ggsave("outputs/ev_saturation_by_population.png", bg = "grey")

LS0tDQp0aXRsZTogIkVWIEluZnJhc3RydWN0dXJlIENsZWFuaW5nIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KRXhlY3V0aXZlIFN1bW1hcnkNCg0KVGhlIGdvYWwgb2YgdGhpcyBwcm9qZWN0IGlzIHRvIGRldGVybWluZSB0aGUgc3RhdGVzIHRoYXQgYXJlIG1vc3QgaW4gbmVlZCBvZiBlbGVjdHJpYyB2ZWhpY2xlIHN0YXRpb25zIGJhc2VkIG9uIGEgbnVtYmVyIG9mIGZhY3RvcnMuDQpUaGVzZSBmYWN0b3JzIGluY2x1ZGUgdGhlIGN1cnJlbnQgbnVtYmVyIG9mIHN0YXRpb25zLCBudW1iZXIgb2YgZWxlY3RyaWMgdmVoaWNsZSByZWdpc3RyYXRpb25zLCBhbmQgc3RhdGUgcG9wdWxhdGlvbi4NClJlc3VsdHMgZnJvbSB0aGlzIHByb2plY3Qgc2hvdWxkIGlkZW50aWZ5IHRoZSBzdGF0ZXMgbW9zdCBpbiBuZWVkIG9mIGFkZGluZyBlbGVjdHJpYyB2ZWhpY2xlIGNoYXJnaW5nIHN0YXRpb25zLg0KDQotLS0NCg0KUGFydCAxOiBDbGVhbmluZyAmIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXMNCg0KLS0tDQoNCmltcG9ydCBsaWJyYXJpZXMgYW5kIGRhdGFzZXQNCkVWIFN0YXRpb24gRGF0YTogaHR0cHM6Ly9hZmRjLmVuZXJneS5nb3YvZGF0YV9kb3dubG9hZA0KDQpgYGB7cn0NCg0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShqYW5pdG9yKQ0KbGlicmFyeShIbWlzYykNCmxpYnJhcnkoZ2dwbG90MikNCg0KYWx0X2Z1ZWxfc3RhdGlvbnMgPC0gcmVhZF9jc3YoImRhdGEvYWx0X2Z1ZWxfc3RhdGlvbnMgKEp1bCA3IDIwMjUpLmNzdiIpDQphbHRfZnVlbF9zdGF0aW9ucw0KYGBgDQoNCnNldCByYW5kb20gc3RhdGUgc2VlZA0KDQpgYGB7cn0NCnNldC5zZWVkKDQyKQ0KYGBgDQoNCg0KY2xlYW4gY29sdW1ucyBuYW1lcyB1c2luZyBqYW5pdG9yDQoNCmBgYHtyfQ0KYWx0X2Z1ZWxfc3RhdGlvbnNfY2xlYW4gPC0gY2xlYW5fbmFtZXMoYWx0X2Z1ZWxfc3RhdGlvbnMpDQoNCmFsdF9mdWVsX3N0YXRpb25zX2NsZWFuDQpgYGANCg0KZmlsdGVyIHRvIG9ubHkgRVYgc3RhdGlvbnMgKCJFTEVDIikNCg0KYGBge3J9DQpldl9zdGF0aW9ucyA8LSBmaWx0ZXIoYWx0X2Z1ZWxfc3RhdGlvbnNfY2xlYW4sIGZ1ZWxfdHlwZV9jb2RlID09ICJFTEVDIikNCg0KZXZfc3RhdGlvbnMNCmBgYA0KDQp0YWtlIGEgbG9vayBhdCB0aGUgdmFsdWVzDQoNCmBgYHtyfQ0Kc3VtbWFyeShldl9zdGF0aW9ucykNCmBgYA0KDQpzZWxlY3QgY29sdW1ucyBmb3Igc3R1ZHkgKHNpbXBsZSBzZXQgYXQgZmlyc3QpDQpnb2FsOiB3aGVyZSBhcmUgdGhlIHN0YXRpb25zLCBob3cgbWFueSBvZiB0aGVtIGFyZSB0aGVyZSBwZXIgc3RhdGUNCg0KYGBge3J9DQpldl9zdGF0aW9uc19zZWxlY3RlZCA8LSBldl9zdGF0aW9ucyB8Pg0KICBzZWxlY3Qoc3RhdGlvbl9uYW1lLCBjaXR5LCBzdGF0ZSwgemlwLCBjb3VudHJ5LCBsYXRpdHVkZSwgbG9uZ2l0dWRlLCBldl9uZXR3b3JrKQ0KDQpldl9zdGF0aW9uc19zZWxlY3RlZA0KYGBgDQoNCmxvb2sgYXQgc2VsZWN0ZWQgY29sdW1ucw0KDQpgYGB7cn0NCnN1bW1hcnkoZXZfc3RhdGlvbnNfc2VsZWN0ZWQpDQoNCmBgYA0KDQpjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMNCg0KYGBge3J9DQpzdW0oaXMubmEoZXZfc3RhdGlvbnNfc2VsZWN0ZWQpKQ0KYGBgDQoNCm5vdywganVzdCBVUyBtYXJrZXQgDQoNCmBgYHtyfQ0KZXZfc3RhdGlvbnNfdXMgPC0gZmlsdGVyKGV2X3N0YXRpb25zX3NlbGVjdGVkLCBjb3VudHJ5ID09ICJVUyIpDQpldl9zdGF0aW9uc191cw0KYGBgDQoNCmxvb2sgYXQgZGlmZmVyZW50IG5ldHdvcmtzIChjaGVja2luZyBmb3IgVGVzbGEgYW5kIEVsZWN0cmlmeSBBbWVyaWNhKQ0KDQpgYGB7cn0NCmV2X25ldHdvcmtzIDwtIGV2X3N0YXRpb25zX3VzWyAsImV2X25ldHdvcmsiXQ0KdGFibGUoZXZfbmV0d29ya3MpDQpgYGANCg0KZmlsdGVyIHRvIG9ubHkgY29udGlndW91cyBVUyBmb3IgZ2Vvc3BhdGlhbCBhbmFseXNpcw0KDQpFWFBPUlQgRk9SIEdFT1NQQVRJQUwgQU5BTFlTSVMNCg0KYGBge3J9DQpldl9zdGF0aW9uc19nZW8gPC0gZXZfc3RhdGlvbnNfdXMgfD4NCiAgZmlsdGVyKCFzdGF0ZSAlaW4lIGMoIkFLIiwgIlBSIiwgIkhJIikpDQoNCnVuaXF1ZShldl9zdGF0aW9uc19nZW8kc3RhdGUpDQoNCndyaXRlLmNzdihldl9zdGF0aW9uc19nZW8sICJkYXRhL2V2X3N0YXRpb25fbG9jYXRpb25zLmNzdiIpDQoNCmBgYA0KDQpicmVha2Rvd24gYnkgc3RhdGUgZm9yIHVwY29taW5nIGpvaW5zDQoNCmBgYHtyfQ0KZXZfc3RhdGlvbnNfYnlfc3RhdGUgPC0gZXZfc3RhdGlvbnNfdXMgfD4NCiAgZ3JvdXBfYnkoc3RhdGUpIHw+DQogIHN1bW1hcmlzZSh0b3RhbF9zdGF0aW9ucyA9IG4oKSkgfD4NCiAgYXJyYW5nZShkZXNjKHRvdGFsX3N0YXRpb25zKSkNCg0KZXZfc3RhdGlvbnNfYnlfc3RhdGUNCmBgYA0KDQpmb3IgcGxvdHRpbmcgKHRvcCAxMCBvbmx5KQ0KDQpgYGB7cn0NCmV2X3N0YXRpb25zX2J5X3N0YXRlXzEwIDwtIGV2X3N0YXRpb25zX3VzIHw+DQogIGdyb3VwX2J5KHN0YXRlKSB8Pg0KICBzdW1tYXJpc2UodG90YWxfc3RhdGlvbnMgPSBuKCkpIHw+DQogIGFycmFuZ2UoZGVzYyh0b3RhbF9zdGF0aW9ucykpIHw+DQogIGhlYWQoMTApDQpgYGANCg0KdGltZSB0byBwbG90DQoNCmBgYHtyfQ0KDQpnZ3Bsb3QoZXZfc3RhdGlvbnNfYnlfc3RhdGVfMTAsIGFlcyh4ID0gcmVvcmRlcihzdGF0ZSwgLXRvdGFsX3N0YXRpb25zKSwgeSA9IHRvdGFsX3N0YXRpb25zKSkgKyANCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic3RlZWxibHVlIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlRvcCAxMCBTdGF0ZXMgYnkgVG90YWwgRVYgU3RhdGlvbnMiLA0KICAgIHggPSAiU3RhdGUiLA0KICAgIHkgPSAiRVYgU3RhdGlvbnMiDQogICkgKyANCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHRvdGFsX3N0YXRpb25zKSwgdmp1c3QgPSAtMC4yKQ0KZ2dzYXZlKCJvdXRwdXRzL3RvcF8xMF9zdGF0ZXNfdG90YWxfZXZfc3RhdGlvbnMucG5nIikNCmBgYA0KDQp2aXN1YWxpemUgVVMgY2hhcmdpbmcgc3RhdGlvbnMNCg0KYGBge3J9DQpsaWJyYXJ5KG1hcHMpDQoNCmdncGxvdChldl9zdGF0aW9uc191cywgYWVzKHggPSBsb25naXR1ZGUsIHkgPSBsYXRpdHVkZSkpICsNCiAgYm9yZGVycygic3RhdGUiKSArDQogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjIsIGNvbG9yID0gImdyZWVuIiwgc2l6ZSA9IDAuMykgKw0KICBjb29yZF9maXhlZCgxLjMpICsgDQogIGxhYnModGl0bGUgPSAiVVMgRVYgQ2hhcmdpbmcgU3RhdGlvbnMiKQ0KDQpnZ3NhdmUoIm91dHB1dHMvdXNfZXZfY2hhcmdpbmdfc3RhdGlvbl9tYXAucG5nIikNCmBgYA0KDQppbXBvcnQgZGF0YSBvbiBudW1iZXIgb2YgdmVoaWNsZSByZWdpc3RyYXRpb25zIGJ5IHN0YXRlDQpFViBSZWdpc3RyYXRpb24gRGF0YTogaHR0cHM6Ly9hZmRjLmVuZXJneS5nb3YvZGF0YS8xMDk2Mg0KDQpgYGB7cn0NCmV2X3JlZ2lzdHJhdGlvbnMgPC0gcmVhZF9jc3YoImRhdGEvZXZfcmVnaXN0cmF0aW9uX2J5X3N0YXRlLmNzdiIpDQpldl9yZWdpc3RyYXRpb25zIDwtIGNsZWFuX25hbWVzKGV2X3JlZ2lzdHJhdGlvbnMpDQpldl9yZWdpc3RyYXRpb25zDQpgYGANCg0KZHJvcCB0b3RhbCBhbmQgREMgcm93cw0KDQpgYGB7cn0NCmV2X3JlZ2lzdHJhdGlvbnNfNTAgPC0gZXZfcmVnaXN0cmF0aW9uc1shKGV2X3JlZ2lzdHJhdGlvbnMkc3RhdGUpICVpbiUgYygiRGlzdHJpY3Qgb2YgQ29sdW1iaWEiLCAiVG90YWwiKSxdDQpldl9yZWdpc3RyYXRpb25zXzUwDQpgYGANCg0KY2hhbmdlIHN0YXRlIG5hbWVzIHRvIGFiYnJldmlhdGlvbnMNCg0KYGBge3J9DQpldl9yZWdpc3RyYXRpb25zXzUwJHN0YXRlIDwtIHN0YXRlLmFiYlttYXRjaChldl9yZWdpc3RyYXRpb25zXzUwJHN0YXRlLCBzdGF0ZS5uYW1lKV0NCmV2X3JlZ2lzdHJhdGlvbnNfNTANCmBgYA0KDQpjb21wYXJlIHRvdGFsIG51bWJlciBvZiBldiBzdGF0aW9ucyB0byBudW1iZXIgb2YgcmVnaXN0cmF0aW9ucyBieSBqb2luaW5nIG9uIHN0YXRlDQpkcm9wIFBSIGFuZCBEQw0KDQpgYGB7cn0NCmV2X2NvbWJpbmVkIDwtIGV2X3N0YXRpb25zX2J5X3N0YXRlIHw+DQogIGxlZnRfam9pbihldl9yZWdpc3RyYXRpb25zXzUwKQ0KDQpldl9jb21iaW5lZCA8LSBldl9jb21iaW5lZFshKGV2X2NvbWJpbmVkJHN0YXRlKSAlaW4lIGMoIlBSIiwgIkRDIiksXQ0KDQpldl9jb21iaW5lZA0KYGBgDQoNCnNvcnQgYnkgcmVnaXN0cmF0aW9ucywgZGVzY2VuZGluZw0KDQpgYGB7cn0NCmV2X2NvbWJpbmVkIDwtIGV2X2NvbWJpbmVkIHw+DQogIGFycmFuZ2UoZGVzYyhldl9jb21iaW5lZCRyZWdpc3RyYXRpb25fY291bnQpKQ0KDQpldl9jb21iaW5lZA0KYGBgDQoNCmltcG9ydCBwb3B1bGF0aW9uIGluZm9ybWF0aW9uDQoNClN0YXRlIFBvcHVsYXRpb24gRGF0YTogaHR0cHM6Ly93d3cuY2Vuc3VzLmdvdi9kYXRhL3RhYmxlcy90aW1lLXNlcmllcy9kZW1vL3BvcGVzdC8yMDIwcy1zdGF0ZS10b3RhbC5odG1sDQoNCmBgYHtyfQ0Kc3RhdGVfcG9wdWxhdGlvbnMgPC0gcmVhZF9jc3YoImRhdGEvc3RhdGVfcG9wdWxhdGlvbnMuY3N2IikNCnN0YXRlX3BvcHVsYXRpb25zDQpgYGANCg0KY2hhbmdlIHN0YXRlIG5hbWVzIHRvIGFiYnJldmlhdGlvbnMsIGFnYWluDQoNCmBgYHtyfQ0Kc3RhdGVfcG9wdWxhdGlvbnMkc3RhdGUgPC0gc3RhdGUuYWJiW21hdGNoKHN0YXRlX3BvcHVsYXRpb25zJHN0YXRlLCBzdGF0ZS5uYW1lKV0NCnN0YXRlX3BvcHVsYXRpb25zDQpgYGANCg0Kam9pbiBwb3B1bGF0aW9uIGRhdGEgdG8gZXhpc3RpbmcgY29tYmluZWQgZGF0YXNldA0KDQpgYGB7cn0NCmV2X2NvbWJpbmVkX3BvcCA8LSBldl9jb21iaW5lZCB8Pg0KICBsZWZ0X2pvaW4oc3RhdGVfcG9wdWxhdGlvbnMpDQoNCmV2X2NvbWJpbmVkX3BvcCANCmBgYA0KDQpiZWdpbiBzaW1wbGUgYW5hbHlzaXMNCg0KZ29hbDogY2FsY3VsYXRlIGVsZWN0cmljIHZlaGljbGVzIHBlciBzdGF0aW9uIGZvciBlYWNoIHN0YXRlDQoNCmBgYHtyfQ0KZXZfY29tYmluZWRfcG9wIDwtIGV2X2NvbWJpbmVkX3BvcCB8Pg0KICBtdXRhdGUoZXZzX3Blcl9zdGF0aW9uID0gcm91bmQocmVnaXN0cmF0aW9uX2NvdW50IC8gdG90YWxfc3RhdGlvbnMsIDIpKSB8Pg0KICBhcnJhbmdlKGRlc2MoZXZzX3Blcl9zdGF0aW9uKSkNCg0KZXZfY29tYmluZWRfcG9wDQpgYGANCg0KZ29hbDogY2FsY3VsYXRlIG51bWJlciBvZiBwZW9wbGUgcGVyIHN0YXRpb24gYmFzZWQgb24gcG9wdWxhdGlvbg0KDQpgYGB7cn0NCmV2X2NvbWJpbmVkX3BvcCA8LSBldl9jb21iaW5lZF9wb3AgfD4NCiAgbXV0YXRlKHBlb3BsZV9wZXJfc3RhdGlvbiA9IHJvdW5kKHBvcHVsYXRpb24gLyB0b3RhbF9zdGF0aW9ucywgMikpIHw+DQogIGFycmFuZ2UoZGVzYyhwZW9wbGVfcGVyX3N0YXRpb24pKQ0KDQpldl9jb21iaW5lZF9wb3ANCmBgYA0KDQpnb2FsOiBjYWxjdWxhdGUgcGVyY2VudGFnZSBvZiBwb3B1bGF0aW9uIHdpdGggYW4gRVYgKHJvdWdoIGVzdGltYXRlIGFzIHBvcHVsYXRpb24gaW5jbHVkZXMgYWxsIGFnZXMgYW5kIHNvbWUgb3duZXJzIG1heSBoYXZlIG1vcmUgdGhhbiBvbmUgRVYpDQoNCmBgYHtyfQ0KZXZfY29tYmluZWRfcG9wIDwtIGV2X2NvbWJpbmVkX3BvcCB8Pg0KICBtdXRhdGUocG9wX3dpdGhfZXYgPSByb3VuZChyZWdpc3RyYXRpb25fY291bnQgLyBwb3B1bGF0aW9uLCA0KSkgfD4NCiAgYXJyYW5nZShkZXNjKHBvcF93aXRoX2V2KSkNCg0KZXZfY29tYmluZWRfcG9wDQoNCmV2X3N0YXRzIDwtIGV2X2NvbWJpbmVkX3BvcCAjIGZvciBsYXRlciB1c2UNCmBgYA0KDQpleHBvcnQgZmluYWxpemVkIGRhdGEgZnJhbWUgZm9yIG1vZGVsaW5nDQoNCmBgYHtyfQ0Kd3JpdGUuY3N2KGV2X2NvbWJpbmVkX3BvcCwgImRhdGEvZXZfY29tYmluZWRfcG9wLmNzdiIpDQp3cml0ZS5jc3YoZXZfc3RhdHMsICJkYXRhL2V2X3N0YXRzLmNzdiIpDQpgYGANCg0KDQp2aXN1YWxpemUgd2l0aCBoZWF0IG1hcA0Kc2hvdyBzdGF0ZXMgd2l0aCBsYXJnZXN0IHByb3BvcnRpb24gb2YgRVZzIHRvIHRoZSBhdmFpbGFibGUgY2hhcmdpbmcgc3RhdGlvbnMNCnRoZXNlIHN0YXRlcyBtYXkgYmUgdW5kZXJkZXZlbG9wZWQgYW5kIGluIG5lZWQgb2YgYWRkaXRpb25hbCBFViBzdGF0aW9uIHJvbGxvdXQNCnllbGxvdyBhbmQgb3JhbmdlIHN0YXRlcyBtYXkgbmVlZCBtb3JlIHN0YXRpb25zIGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgdmVoaWNsZXMgY3VycmVudGx5IHJlZ2lzdGVyZWQNCg0KYGBge3J9DQpsaWJyYXJ5KHVzbWFwKQ0KDQpwbG90X3VzbWFwKGRhdGEgPSBldl9jb21iaW5lZF9wb3AsIHZhbHVlcyA9ICJldnNfcGVyX3N0YXRpb24iLCBjb2xvciA9ICJ3aGl0ZSIpICsgDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJDIikgKw0KICBsYWJzKHRpdGxlID0gIkVWcyBQZXIgQ2hhcmdpbmcgU3RhdGlvbiBpbiB0aGUgVVMiLA0KICAgICAgIGZpbGwgPSAiRVZzL1N0YXRpb24iKQ0KDQpnZ3NhdmUoIm91dHB1dHMvZXZzX3Blcl9jaGFyZ2luZ19zdGF0aW9uX3VzLnBuZyIsIGJnID0gImdyZXkiKQ0KDQpgYGANCg0KdmlzdWFsaXplIHdpdGggaGVhdCBtYXANCnNob3cgc3RhdGVzIHdpdGggdGhlIGxhcmdlc3QgcHJvcG9ydGlvbiBvZiBwZW9wbGUgdG8gdGhlIGF2YWlsYWJsZSBjaGFyZ2luZyBzdGF0aW9ucw0KdGhlc2Ugc3RhdGVzIGhhdmUgdGhlIGhpZ2hlc3QgcG9wdWxhdGlvbnMgcmVsYXRpdmUgdG8gdGhlIG51bWJlciBvZiBzdGF0aW9ucw0KeWVsbG93IGFuZCBvcmFuZ2Ugc3RhdGVzIG1heSBiZSBpbiBuZWVkIG9mIG1vcmUgRVYgc3RhdGlvbnMgYmFzZWQgb24gc3RhdGUgcG9wdWxhdGlvbg0KDQpgYGB7cn0NCnBsb3RfdXNtYXAoZGF0YSA9IGV2X2NvbWJpbmVkX3BvcCwgdmFsdWVzID0gInBlb3BsZV9wZXJfc3RhdGlvbiIsIGNvbG9yID0gIndoaXRlIikgKyANCiAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uID0gIkMiKSArDQogIGxhYnModGl0bGUgPSAiUGVvcGxlIFBlciBDaGFyZ2luZyBTdGF0aW9uIGluIHRoZSBVUyIsDQogICAgICAgZmlsbCA9ICJQZW9wbGUvU3RhdGlvbiIpDQoNCmdnc2F2ZSgib3V0cHV0cy9wZW9wbGVfcGVyX2NoYXJnaW5nX3N0YXRpb25fdXMucG5nIiwgYmcgPSAiZ3JleSIpDQoNCmBgYA0KDQp2aXN1YWxpemUgd2l0aCBoZWF0IG1hcA0Kc2hvdyBzdGF0ZXMgd2l0aCB0aGUgbGFyZ2VzdCBoaWdoZXN0IEVWIHNhdHVyYXRpb24gKEVWIHJlZ2lzdHJhdGlvbnMgLyBwb3B1bGF0aW9uKQ0KeWVsbG93IGFuZCBvcmFuZ2Ugc3RhdGVzIGNvdWxkIGJlIGNvbnNpZGVyZWQgdGhlIGZhc3Rlci1ncm93aW5nIG1hcmtldHMgY29tcGFyZWQgdG8gcHVycGxlIGFuZCBibHVlIHN0YXRlcw0KYXMgZXhwZWN0ZWQsIENhbGlmb3JuaWEgaGFzIHRoZSBoaWdoZXN0IHNhdHVyYXRpb24gb2YgRVZzIGZvbGxvd2VkIGJ5IG90aGVyIFBhY2lmaWMgQ29hc3Qgc3RhdGVzDQpvdGhlciBzdGF0ZXMgbWF5IHNlZSBqdW1wcyBpbiBzYXR1cmF0aW9uIGluIHRoZSBjb21pbmcgZGVjYWRlcyBhbmQgd291bGQgcmVxdWlyZSBhZGRpdGlvbmFsIEVWIHN0YXRpb25zDQoNCmBgYHtyfQ0KcGxvdF91c21hcChkYXRhID0gZXZfY29tYmluZWRfcG9wLCB2YWx1ZXMgPSAicG9wX3dpdGhfZXYiLCBjb2xvciA9ICJ3aGl0ZSIpICsgDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG9wdGlvbiA9ICJDIikgKw0KICBsYWJzKHRpdGxlID0gIkVWIFNhdHVyYXRpb24gYnkgUG9wdWxhdGlvbiIsDQogICAgICAgZmlsbCA9ICJFViBSZWcvUG9wIikNCg0KZ2dzYXZlKCJvdXRwdXRzL2V2X3NhdHVyYXRpb25fYnlfcG9wdWxhdGlvbi5wbmciLCBiZyA9ICJncmV5IikNCg0KYGBgDQo=